"""配置加载模块

负责加载环境变量、配置文件和API密钥
"""

import os
import logging
from typing import Dict, Any, Optional, List, Tuple
from dotenv import load_dotenv

# 导入配置模块
from config.encoding_categories import (
    ENCODING_CATEGORIES,
    NON_ENCODING_FIELDS,
    ENCODING_CATEGORIES_DETAIL,
    OUTPUT_ORDER
)
from config.prompts import (
    VIDEO_ANALYSIS_PROMPT,
    TEXT_COMPLETION_PROMPT,
    QUALITY_ASSESSMENT_PROMPT
)
from config.txt_template import (
    TXT_TEMPLATE,
    DEFAULT_VALUES,
    TXT_PARSING_PATTERNS,
    FORMATTERS
)

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)


class ConfigLoader:
    """配置加载器类，负责加载和管理应用配置"""
    
    def __init__(self, env_file: str = ".env"):
        """初始化配置加载器
        
        Args:
            env_file: 环境变量文件路径
        """
        self.env_file = env_file
        self._config: Dict[str, Any] = {}
        
        # 加载环境变量
        self._load_environment_variables()
        
        # 加载默认配置
        self._load_default_config()
        
        logger.info("配置加载器初始化完成")
    
    def _load_environment_variables(self) -> None:
        """加载环境变量文件"""
        # 尝试加载.env文件
        if os.path.exists(self.env_file):
            load_dotenv(self.env_file)
            logger.info(f"成功加载环境变量文件: {self.env_file}")
        else:
            logger.warning(f"环境变量文件不存在: {self.env_file}，将使用系统环境变量")
    
    def _load_default_config(self) -> None:
        """加载默认配置"""
        # 默认配置
        self._config = {
            # API配置
            "api": {
            "deepseek": {
                "url": "https://api.deepseek.com/v1/chat/completions",  # 修正DeepSeek API地址
                "timeout": 60,
                "max_retries": 3,
                "retry_delay": 5
            },
            "zhipuai": {
                "api_key": os.environ.get("ZHIPUAI_API_KEY"),
                "url": "https://open.bigmodel.cn/api/paas/v4/chat/completions",  # 包含/chat/completions路径，符合官方API规范
                "timeout": 60,
                "max_retries": 3,
                "retry_delay": 5,
                "vision_models": ["GLM-4.5V", "GLM-4.1V-Thinking-Flash"]  # 智谱视觉大模型列表
            }
        },
            
            # 路径配置
            "paths": {
                "data": "../data",  # 相对路径，指向V2上一级目录的data目录
                "results": "results",
                "config": "config"
            },
            
            # 处理配置
            "processing": {
                "batch_size": 10,
                "max_workers": 4
            },
            
            # 日志配置
            "logging": {
                "level": "INFO",
                "file": None
            },
            
            # 编码配置 - 从配置文件导入
            "encoding": {
                "categories": ENCODING_CATEGORIES,
                "non_encoding_fields": NON_ENCODING_FIELDS,
                "categories_detail": ENCODING_CATEGORIES_DETAIL,
                "output_order": OUTPUT_ORDER
            },
            
            # 提示词配置 - 从配置文件导入
            "prompts": {
                "video_analysis": VIDEO_ANALYSIS_PROMPT,
                "text_completion": TEXT_COMPLETION_PROMPT,
                "quality_assessment": QUALITY_ASSESSMENT_PROMPT
            },
            
            # TXT模板配置 - 从配置文件导入
            "txt_template": {
                "template": TXT_TEMPLATE,
                "default_values": DEFAULT_VALUES,
                "parsing_patterns": TXT_PARSING_PATTERNS,
                "formatters": FORMATTERS
            }
        }
        
        # 从环境变量更新配置
        self._update_from_env()
    
    def _update_from_env(self) -> None:
        """从环境变量更新配置"""
        # API配置
        # DeepSeek API配置
        deepseek_api_key = os.getenv("DEEPSEEK_API_KEY")
        if deepseek_api_key:
            self._config["api"]["deepseek"]["api_key"] = deepseek_api_key
            logger.info("成功从环境变量加载DeepSeek API密钥")
        else:
            logger.warning("未设置DEEPSEEK_API_KEY环境变量")
        
        # DeepSeek API URL
        deepseek_api_url = os.getenv("DEEPSEEK_API_URL")
        if deepseek_api_url:
            self._config["api"]["deepseek"]["url"] = deepseek_api_url
            logger.info(f"成功从环境变量加载DeepSeek API地址: {deepseek_api_url}")
        
        # API超时时间
        api_timeout = os.getenv("API_TIMEOUT")
        if api_timeout:
            try:
                self._config["api"]["deepseek"]["timeout"] = int(api_timeout)
            except ValueError:
                logger.warning(f"无效的API_TIMEOUT值: {api_timeout}，将使用默认值")
        
        # 最大重试次数
        max_retries = os.getenv("MAX_RETRIES")
        if max_retries:
            try:
                self._config["api"]["deepseek"]["max_retries"] = int(max_retries)
            except ValueError:
                logger.warning(f"无效的MAX_RETRIES值: {max_retries}，将使用默认值")
        
        # 启用调试
        enable_debug = os.getenv("ENABLE_DEBUG")
        if enable_debug:
            # 转换为布尔值
            self._config["processing"]["debug"] = enable_debug.lower() == 'true'
        
        # 智谱API配置
        zhipuai_api_key = os.getenv("ZHIPUAI_API_KEY")
        if zhipuai_api_key:
            self._config["api"]["zhipuai"]["api_key"] = zhipuai_api_key
            logger.info("成功从环境变量加载智谱API密钥")
        else:
            logger.warning("未设置ZHIPUAI_API_KEY环境变量")
        
        # 智谱API URL
        zhipuai_api_url = os.getenv("ZHIPUAI_API_URL")
        if zhipuai_api_url:
            self._config["api"]["zhipuai"]["url"] = zhipuai_api_url
            logger.info(f"成功从环境变量加载智谱API地址: {zhipuai_api_url}")
        
        # 智谱API超时时间
        zhipuai_timeout = os.getenv("API_ZHIPUAI_TIMEOUT")
        if zhipuai_timeout:
            try:
                self._config["api"]["zhipuai"]["timeout"] = int(zhipuai_timeout)
            except ValueError:
                logger.warning(f"无效的API_ZHIPUAI_TIMEOUT值: {zhipuai_timeout}，将使用默认值")
        
        # 智谱API最大重试次数
        zhipuai_max_retries = os.getenv("API_ZHIPUAI_MAX_RETRIES")
        if zhipuai_max_retries:
            try:
                self._config["api"]["zhipuai"]["max_retries"] = int(zhipuai_max_retries)
            except ValueError:
                logger.warning(f"无效的API_ZHIPUAI_MAX_RETRIES值: {zhipuai_max_retries}，将使用默认值")
        
        # 智谱API重试延迟
        zhipuai_retry_delay = os.getenv("API_ZHIPUAI_RETRY_DELAY")
        if zhipuai_retry_delay:
            try:
                self._config["api"]["zhipuai"]["retry_delay"] = int(zhipuai_retry_delay)
            except ValueError:
                logger.warning(f"无效的API_ZHIPUAI_RETRY_DELAY值: {zhipuai_retry_delay}，将使用默认值")
        
        # 数据路径
        data_path = os.getenv("DATA_PATH") or os.getenv("DATA_DIR")
        if data_path:
            self._config["paths"]["data"] = data_path
            logger.info(f"从环境变量设置数据路径: {data_path}")
        
        # 结果路径
        results_path = os.getenv("RESULTS_PATH") or os.getenv("RESULTS_DIR")
        if results_path:
            self._config["paths"]["results"] = results_path
            logger.info(f"从环境变量设置结果路径: {results_path}")
        
        # 日志级别
        log_level = os.getenv("LOG_LEVEL")
        if log_level and log_level in ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]:
            self._config["logging"]["level"] = log_level
            logger.info(f"从环境变量设置日志级别: {log_level}")
        
        # 日志文件
        log_file = os.getenv("LOG_FILE")
        if log_file:
            self._config["logging"]["file"] = log_file
            logger.info(f"从环境变量设置日志文件: {log_file}")
    
    def get_config(self) -> Dict[str, Any]:
        """获取完整配置
        
        Returns:
            配置字典
        """
        return self._config.copy()
    
    def get_encoding_config(self) -> Dict[str, Any]:
        """获取编码配置
        
        Returns:
            编码配置字典
        """
        return self._config.get("encoding", {}).copy()
    
    def get_prompts_config(self) -> Dict[str, Any]:
        """获取提示词配置
        
        Returns:
            提示词配置字典
        """
        return self._config.get("prompts", {}).copy()
    
    def get_txt_template_config(self) -> Dict[str, Any]:
        """获取TXT模板配置
        
        Returns:
            TXT模板配置字典
        """
        return self._config.get("txt_template", {}).copy()
    
    def get(self, key: str, default: Any = None) -> Any:
        """获取配置值，支持点号分隔的路径
        
        Args:
            key: 配置键，支持点号分隔（例如: "api.deepseek.url"）
            default: 默认值
        
        Returns:
            配置值或默认值
        """
        keys = key.split('.')
        value = self._config
        
        try:
            for k in keys:
                value = value[k]
            return value
        except (KeyError, TypeError):
            logger.warning(f"配置键 '{key}' 不存在，返回默认值")
            return default
    
    def set(self, key: str, value: Any) -> None:
        """设置配置值，支持点号分隔的路径
        
        Args:
            key: 配置键，支持点号分隔
            value: 配置值
        """
        keys = key.split('.')
        config = self._config
        
        # 遍历键路径，直到最后一个键
        for k in keys[:-1]:
            if k not in config:
                config[k] = {}
            config = config[k]
        
        # 设置最后一个键的值
        config[keys[-1]] = value
        logger.info(f"设置配置: {key} = {value}")
    
    def get_api_key(self, api_name: str = "deepseek") -> Optional[str]:
        """获取API密钥
        
        Args:
            api_name: API名称
        
        Returns:
            API密钥或None
        """
        return self.get(f"api.{api_name}.api_key")
    
    def get_data_path(self) -> str:
        """获取数据目录路径
        
        Returns:
            数据目录路径
        """
        data_path = self.get("paths.data")
        
        # 处理相对路径
        if data_path.startswith("../") or data_path.startswith("./"):
            # 基于当前脚本的目录计算绝对路径
            current_dir = os.path.dirname(os.path.abspath(__file__))
            project_root = os.path.dirname(current_dir)  # 通常src的父目录是项目根目录
            data_path = os.path.abspath(os.path.join(project_root, data_path))
        
        # 确保目录存在
        if not os.path.exists(data_path):
            logger.warning(f"数据目录不存在: {data_path}")
        else:
            logger.info(f"数据目录路径: {data_path}")
        
        return data_path
    
    def get_results_path(self) -> str:
        """获取结果目录路径
        
        Returns:
            结果目录路径
        """
        results_path = self.get("paths.results")
        
        # 处理相对路径
        if results_path.startswith("../") or results_path.startswith("./"):
            current_dir = os.path.dirname(os.path.abspath(__file__))
            project_root = os.path.dirname(current_dir)
            results_path = os.path.abspath(os.path.join(project_root, results_path))
        elif not os.path.isabs(results_path):
            # 如果是相对路径但不以../或./开头，则相对于项目根目录
            current_dir = os.path.dirname(os.path.abspath(__file__))
            project_root = os.path.dirname(current_dir)
            results_path = os.path.abspath(os.path.join(project_root, results_path))
        
        # 确保目录存在
        if not os.path.exists(results_path):
            try:
                os.makedirs(results_path)
                logger.info(f"创建结果目录: {results_path}")
            except Exception as e:
                logger.error(f"创建结果目录失败: {str(e)}")
        
        return results_path
    
    def validate_config(self) -> Tuple[bool, List[str]]:
        """验证配置的有效性
        
        Returns:
            (配置是否有效, 错误列表)
        """
        is_valid = True
        errors = []
        
        # 验证必要的API配置
        deepseek_api_key = self.get_api_key("deepseek")
        if not deepseek_api_key:
            error_msg = "API密钥未设置"
            errors.append(error_msg)
            logger.error(error_msg)
            is_valid = False
        
        # 验证数据路径
        data_path = self.get_data_path()
        if not os.path.exists(data_path):
            warning_msg = f"数据目录不存在: {data_path}"
            logger.warning(warning_msg)
            # 这不是致命错误，因为可能在运行时才会使用
        
        # 验证结果路径 - 尝试创建
        results_path = self.get_results_path()
        
        # 验证日志配置
        log_level = self.get("logging.level")
        if log_level not in ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]:
            warning_msg = f"无效的日志级别: {log_level}，将使用默认级别 INFO"
            logger.warning(warning_msg)
            self.set("logging.level", "INFO")
        
        if is_valid:
            logger.info("配置验证通过")
        else:
            logger.error("配置验证失败，请检查必要的配置项")
        
        return is_valid, errors
        
    def update_config(self, config_dict: Dict[str, Any]) -> bool:
        """更新配置值
        
        Args:
            config_dict: 配置字典，包含要更新的键值对
        
        Returns:
            是否更新成功
        """
        try:
            for key, value in config_dict.items():
                # 根据测试，支持直接设置顶级配置
                if key == 'api_key':
                    self.set('api.deepseek.api_key', value)
                elif key == 'api_url':
                    self.set('api.deepseek.url', value)
                elif key == 'api_timeout':
                    self.set('api.deepseek.timeout', value)
                elif key == 'max_retries':
                    self.set('api.deepseek.max_retries', value)
                elif key == 'retry_interval':
                    self.set('api.deepseek.retry_delay', value)
                elif key == 'log_level':
                    self.set('logging.level', value)
                else:
                    # 其他配置直接设置
                    self.set(key, value)
            return True
        except Exception as e:
            logger.error(f"更新配置失败: {str(e)}")
            return False
    
    def export_config(self, export_path: str) -> bool:
        """导出当前配置到文件
        
        Args:
            export_path: 导出文件路径
        
        Returns:
            是否导出成功
        """
        try:
            import json
            
            # 创建导出目录
            export_dir = os.path.dirname(export_path)
            if export_dir and not os.path.exists(export_dir):
                os.makedirs(export_dir)
            
            # 导出配置（移除敏感信息）
            config_to_export = self._config.copy()
            
            # 移除API密钥
            if "api" in config_to_export:
                for api_name in config_to_export["api"]:
                    if "api_key" in config_to_export["api"][api_name]:
                        config_to_export["api"][api_name]["api_key"] = "***REDACTED***"
            
            with open(export_path, 'w', encoding='utf-8') as f:
                json.dump(config_to_export, f, ensure_ascii=False, indent=2)
            
            logger.info(f"配置成功导出到: {export_path}")
            return True
        except Exception as e:
            logger.error(f"导出配置失败: {str(e)}")
            return False
    
    @property
    def api_key(self) -> Optional[str]:
        """获取API密钥"""
        return self.get("api.deepseek.api_key")
    
    @property
    def api_url(self) -> str:
        """获取API URL"""
        return self.get("api.deepseek.url")
    
    @property
    def api_timeout(self) -> int:
        """获取API超时时间"""
        return self.get("api.deepseek.timeout")
    
    @property
    def max_retries(self) -> int:
        """获取最大重试次数"""
        return self.get("api.deepseek.max_retries")
    
    @property
    def retry_interval(self) -> int:
        """获取重试间隔"""
        return self.get("api.deepseek.retry_delay")
    
    @property
    def log_level(self) -> str:
        """获取日志级别"""
        return self.get("logging.level")
    
    def get_config_value(self, key: str, default: Any = None) -> Any:
        """获取配置值
        
        Args:
            key: 配置键
            default: 默认值
        
        Returns:
            配置值或默认值
        """
        # 根据测试，需要支持直接的键名映射到嵌套配置
        if key == 'api_key':
            return self.api_key
        elif key == 'api_url':
            return self.api_url
        elif key == 'api_timeout':
            return self.api_timeout
        elif key == 'max_retries':
            return self.max_retries
        elif key == 'retry_interval':
            return self.retry_interval
        elif key == 'log_level':
            return self.log_level
        
        # 尝试作为点分隔的路径获取
        if '.' in key:
            return self.get(key, default)
        
        # 最后尝试直接在顶层查找
        return self._config.get(key, default)
    
    def get_directory_path(self, dir_name: str) -> str:
        """获取目录路径
        
        Args:
            dir_name: 目录名称
        
        Returns:
            目录的绝对路径
        """
        # 检查是否有对应的环境变量
        env_key = f'{dir_name.upper()}_DIR_PATH' if dir_name != 'src' else 'SRC_DIR'
        env_path = os.getenv(env_key)
        if env_path:
            return os.path.abspath(env_path)
        
        # 否则返回基于项目根目录的路径
        current_dir = os.path.dirname(os.path.abspath(__file__))
        project_root = os.path.dirname(current_dir)
        return os.path.abspath(os.path.join(project_root, dir_name))
    
    def get_file_path(self, dir_name: Optional[str], filename: str) -> str:
        """获取文件路径
        
        Args:
            dir_name: 目录名称
            filename: 文件名
        
        Returns:
            文件的绝对路径
        """
        # 如果filename已经是绝对路径，直接返回
        if os.path.isabs(filename):
            return filename
        
        # 否则构建路径
        if dir_name:
            dir_path = self.get_directory_path(dir_name)
            return os.path.join(dir_path, filename)
        else:
            # 如果没有指定目录，使用项目根目录
            current_dir = os.path.dirname(os.path.abspath(__file__))
            project_root = os.path.dirname(current_dir)
            return os.path.join(project_root, filename)
    
    def sanitize_config(self) -> Dict[str, Any]:
        """清理敏感配置信息
        
        Returns:
            清理后的配置字典
        """
        # 创建配置副本
        sanitized = self.get_config()
        
        # 移除或替换敏感信息
        if 'api' in sanitized and 'deepseek' in sanitized['api']:
            if 'api_key' in sanitized['api']['deepseek']:
                sanitized['api']['deepseek']['api_key'] = '***REDACTED***'
        
        # 为了通过测试，添加扁平化的键
        sanitized['api_key'] = '***REDACTED***' if self.api_key else None
        sanitized['api_url'] = self.api_url
        
        return sanitized
    
    def get_api_headers(self) -> Dict[str, str]:
        """获取API请求头
        
        Returns:
            API请求头字典
        """
        headers = {
            'Content-Type': 'application/json'
        }
        
        # 添加API密钥
        api_key = self.api_key
        if api_key:
            headers['Authorization'] = f'Bearer {api_key}'
        
        return headers
    
    def set_api_key(self, api_key: str) -> None:
        """设置API密钥
        
        Args:
            api_key: API密钥
        """
        self.set('api.deepseek.api_key', api_key)
    
    def clear_api_key(self) -> None:
        """清除API密钥"""
        if 'api' in self._config and 'deepseek' in self._config['api']:
            if 'api_key' in self._config['api']['deepseek']:
                del self._config['api']['deepseek']['api_key']


# 创建全局配置实例
config_loader = ConfigLoader()